# -*- coding: utf-8 -*-
from chemdb import dbHandle
from dbobject import DBObject
from fingerprint import Fingerprint

class Compound(DBObject):
	"""This is a class that holds all the info that
		we keep about compounds in the database.
		Also it does automatic lookups for things when
		we don't have the info yet.
		PLEASE!!! Refer to things like this!!!!
		Things in this class:
		#pybel mol object
		self.mol

		#Object objects
		self.mol
		self.inchi

		#list of relation objects
		self.products
		self.reactants

		#fingerprint object
		self.fingerprint
	"""

	def __init__(self, name=-1):
		"""Name is either the name of the compound or the id(int)
		"""

		DBObject.__init__(self)

		if type(name) == str:
			self.id = dbHandle.getIdFromName(name)
		else:
			self.id = name

		#dict of items we have (overriding __dict__)
		#mol object
		self._things['mol'] = self.Mol(self.id)

		#string object
		self._things['name'] = ""
		self._things['formula'] = ""
		self._things['IUPACname'] = ""
		self._things['inchi'] = self.Inchi(self.id)

		#list of relation objects
		self._things['products'] = []
		self._things['reactants'] = []

		#fingerprint object
		self._things['fingerprint'] = None

	def _getItem(self, name):
		"""Returns the item and also adds it to the _things dict
		   This is an interal method, please do not use.
		"""
		if self.id == -1:
			return self._things[name]
		if name=="name":
			n = dbHandle.get('name', 'compound', 'id', self.id)
			self._things['name'] = n
			return n
		elif name=="formula":
			formula = dbHandle.get('formula', 'compound', 'id', self.id)
			self._things['formula'] = formula
			return formula
		elif name=="IUPACname":
			IUPACname = dbHandle.get('IUPACname', 'compound', 'id', self.id)
			self._things['IUPACname'] = IUPACname
			return IUPACname
		elif name=="mol":
			molId = dbHandle.get('id', 'compound_mol', 'compound_id', self.id)
			if molId==-1 or None:
				molId = dbHandle.insertMol(self.id)
			self._things['mol'] = self.Mol(molId)
			return self._things['mol']
		elif name=="inchi":
			inchiId = dbHandle.get('id', 'compound_inchi', 'compound_id', self.id)
			if inchiId==-1 or None:
				inchiId = dbHandle.insertInchi(self.id)
			self._things['inchi'] = self.Inchi(inchiId)
			print self._things['inchi']
			return self._things['inchi']
		elif name=="fingerprint":
			fingerprintId = dbHandle.get('id', 'compound_fp', 'compound_id', self.id)
			fp = Fingerprint(fingerprintId)
			self._things['fingerprint'] = fp
			return fp
		elif name=="products":
			productIds = dbHandle.getMany('product_id', 'relation', 'reactant_id', self.id)
			products = [Compound(id) for id in productIds]
			self._things['products'] = products
			return products
		elif name=="reactants":
			reactantIds = dbHandle.getMany('reactant_id', 'relation', 'product_id', self.id)
			reactants = [Compound(id) for id in reactantIds]
			self._things['reactants'] = reactants
			return reactants
		else:
			raise AttributeError, "This shouldn't ever happen..."

	def insert(self):
		if self.id != -1:
			raise AttributeError, "Object already in DB"

		self.id = dbHandle.insertCompound()

		if self._things['mol']:
			self._things['mol'].insert(self.id)
		if self._things['inchi']:
			self._things['inchi'].insert(self.id)

		for i in self._needToUpdate:
			self.updateDB(i)
		self._needToUpdate = []

	def updateDB(self, name):
		if self.id == -1:
			self._needToUpdate.append(name)
			return

		if name == "products" or name == "reactants":
			return 		#these are only here for convience not in db
		elif name == "mol":
			#dbHandle.updateMolfile(self._things["mol"].id, "compound_id", self.id)
			raise Exception
		elif name == "inchi":
			#dbHandle.updateInchi(self._things["inchi"].id, "compound_id", self.id)
			raise Exception
		elif name == "fingerprint":
			dbHandle.updateFingerprint(self._things["fingerprint"].id, "compound_id", self.id)
		elif name == "products" or name == "reactants":
			raise NameError, "Connot set %s." % (name)
		elif name in self._things.keys():
			dbHandle.updateCompound(self.id, name, self._things[name])
		else:
			raise NameError, name

	def addProduct(self, product, reaction=None):
		self.products.append(product)

		if reaction:
			dbHandle.insertRelation(self.id, product.id, reaction.id)
		else:
			dbHandle.insertRelation(self.id, product.id)

	def addReatant(self, reactant, reaction=None):
		self.reactants.append(reactant)

		if reaction:
			dbHandle.insertRelation(reactant.id, self.id, reaction.id)
		else:
			dbHandle.insertRelation(reactant.id, self.id)

	class Mol(DBObject):
		"""This class holds the information for a mol object.
		It has a molfile associated with it. This is basically used
		so we can have fast searching in the database.
		"""
		def __init__(self, id=-1):

			DBObject.__init__(self)

			self.id = id

			self._things['molfile'] = ""

		def _getItem(self, name):

			if name == "molfile":
				f = dbHandle.get('molfile', 'compound_mol', 'id', self.id)
				self._things['molfile'] = f
				return f

		def insert(self, compound_id):
			if self.id != -1:
				raise AttributeError, "Object already in DB"

			self.id = dbHandle.insertMol(compound_id)

			for i in self._needToUpdate:
				self.updateDB(i)
			self._needToUpdate = []

		def updateDB(self, name):
			if self.id == -1:
				self._needToUpdate.append(name)

			if name == "molfile":
				dbHandle.updateMolfile(self.id, "molfile", self._things['molfile'])

	class Inchi(DBObject):
		"""This class holds the information for a mol object.
		It has a molfile associated with it. This is basically used
		so we can have fast searching in the database.
		"""
		def __init__(self, id):

			DBObject.__init__(self)

			self.id = id

			self._things['inchi'] = ""

		def _getItem(self, name):

			if name == "inchi":
				f = dbHandle.get('inchi', 'compound_inchi', 'id', self.id)
				self._things['inchi'] = f
				return f

		def insert(self, compound_id):
			if self.id != -1:
				raise AttributeError, "Object already in DB"

			self.id = dbHandle.insertInchi(compound_id)

			for i in self._needToUpdate:
				self.updateDB(i)
			self._needToUpdate = []

		def updateDB(self, name):
			if self.id == -1:
				self._needToUpdate.append(name)

			if name == "inchi":
				dbHandle.updateInchi(self.id, "inchi", self._things['inchi'])

def searchForCompound(compound):
	query = {}
	if compound.name:
		query['name'] = compound.name
	if compound.formula:
		query['formula'] = compound.formula
	if compound.IUPACname:
		query['IUPACname'] = compound.IUPACname

	ids = dbHandle.searchLike(query, 'compound')

	#TODO make searching on inchi's work
	#inchiIds = []
	#if compound.inchi.inchi:
		#inchiIds = dbHandle.searchByInchi(compound.inchi)

	#for i in inchiIds:
		#if i not in ids:
			#ids.append(i)

	print ids

	return [Compound(i[0]) for i in ids]